﻿using CatUtils.Utils.Helper;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace CatUtils.Utils.Currency.IoUtils
{
    /// <summary>
    /// 文件帮助的主方法
    /// </summary>
    public class FileHelper
    {
        /// <summary>
        /// 用户选择目录记忆保存路径
        /// </summary>
        public static string SelectFileInfoTemp { get; set; } = StaticValue.TempPathSystem + "SelectFileInfoTemp.txt";

        /// <summary>
        /// 判断文件是否存在，并且设定是否创建文件
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <returns>返回为TRUE，文件存在，BOOL 文件不存在。</returns>
        public static bool FileExits(string FilePath)
        {
            return FileExits(FilePath, false);
        }

        /// <summary>
        /// 判断文件是否存在，并且设定是否创建文件
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="CreateFlie">设定参数CreateFlie为True可以同时创建文件</param>
        /// <returns>返回为TRUE，文件存在，BOOL 文件不存在。</returns>
        public static bool FileExits(string FilePath, bool CreateFlie)
        {
            if (File.Exists(FilePath))
            {
                return true;
            }
            else
            {
                if (CreateFlie)
                {
                    try
                    {
                        FloderHelper.FloderExits(Path.GetDirectoryName(FilePath), true);

                        using (File.Create(FilePath))

                            return true;
                    }
                    catch (Exception ex)
                    {
                        PrintLog.E(ex);
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 读取文件，自行指定编码
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <returns>返回读取结果，读取失败或文件为空返回空字符串 ""  请注意判断</returns>
        public static string ReadAllText(string FilePath)
        {
            return ReadAllText(FilePath, Encoding.UTF8, true);
        }

        /// <summary>
        /// 读取文件，自行指定编码
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="encoding">文件编码格式</param>
        /// <returns>返回读取结果，读取失败或文件为空返回空字符串 ""  请注意判断</returns>
        public static string ReadAllText(string FilePath, Encoding encoding)
        {
            return ReadAllText(FilePath, encoding, true);
        }

        /// <summary>
        /// 将文件转换为byte数组 不存在返回new byte[0];
        /// </summary>
        /// <param name="FilePath">文件地址</param>
        /// <returns>转换后的byte数组</returns>
        public static byte[] FileConvertToBytes(string FilePath)
        {
            if (!File.Exists(FilePath))
            {
                PrintLog.E("FileNotExits:" + FilePath);
                return new byte[0];
            }
            try
            {
                FileStream stream = new FileInfo(FilePath).OpenRead();
                byte[] buffer = new byte[stream.Length];
                stream.Read(buffer, 0, buffer.Length);
                stream.Seek(0, SeekOrigin.Begin);
                stream.Dispose();
                return buffer;
            }
            catch (Exception ex)
            {
                PrintLog.E(ex);
            }
            return new byte[0];
        }

        /// <summary>
        /// UTF8 文件移除Bom头 linux支持 否则php无法正常读取某些文件
        //System.Text.Encoding.UTF8 是一个静态实例，它省略了 BOM，而 new UTF8Encoding(false) 创建的实例是含有 BOM 的。
        //BOM，即 Byte Order Mark，也即字节流标记，它是用来让应用程序识别所用的编码的。UTF-8 的 BOM 是 0xEFBBBF。
        //public UTF8Encoding(bool encoderShouldEmitUTF8Identifier)，可以看出，如果我们指定参数为 false，表示不省略 BOM；
        //如果为 true，则和 Encoding.UTF8 一样了。
        //注意，在 msdn 上似乎把这个参数的意思解释反了。有兴趣的朋友可以看一看：http://msdn.microsoft.com/zh-cn/community/s064f8w2.aspx。
        /// </summary>
        /// <param name="FilePath"></param>
        /// <param name="NewFilePath"></param>

        /// <returns></returns>
        public static string RemoveWindowsBomUTF8(string FilePath, string NewFilePath)
        {
            byte[] buffer = FileConvertToBytes(FilePath);
            if (buffer == null || buffer == new byte[0])
                return null;

            if (buffer.Length <= 3)
            {
                return Encoding.UTF8.GetString(buffer);
            }

            byte[] bomBuffer = new byte[] { 0xef, 0xbb, 0xbf };

            if (buffer[0] == bomBuffer[0]
                && buffer[1] == bomBuffer[1]
                && buffer[2] == bomBuffer[2])
            {
                return new UTF8Encoding(false).GetString(buffer, 3, buffer.Length - 3);
            }
            return Encoding.UTF8.GetString(buffer);
        }

        /// <summary>
        /// 读取文件，设定不存在是否创建
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="CreateFlie">设定参数CreateFlie为True可以同时创建文件</param>
        /// <returns>返回读取结果，读取失败或文件为空返回空字符串 ""  请注意判断</returns>
        public static string ReadAllText(string FilePath, bool CreateFlie)
        {
            return ReadAllText(FilePath, Encoding.UTF8, CreateFlie);
        }

        /// <summary>
        /// 读取文件，自行指定编码,并且声明是否创建
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="encoding">文件编码格式</param>
        /// <param name="CreateFlie">设定参数CreateFlie为True可以同时创建文件</param>
        /// <returns>返回读取结果，读取失败或文件为空返回空字符串 ""  请注意判断</returns>
        public static string ReadAllText(string FilePath, Encoding encoding, bool CreateFlie)
        {
            try
            {
                if (FileHelper.FileExits(FilePath, CreateFlie))

                    return File.ReadAllText(FilePath, encoding);
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }
            return "";
        }

        /// <summary>
        /// 追加新文本，默认使用UTF8编码 ，默认追加时换行。
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="Content">文本内容</param>
        /// <returns>追加文本成功返回true</returns>
        public static bool AppendText(string FilePath, string Content)
        {
            return AppendText(FilePath, Content, true);
        }

        /// <summary>
        /// 追加新文本，默认使用UTF8编码
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="Content">文本内容</param>
        /// <param name="NewLine">追加内容时，是否换行。为True换行</param>
        /// <returns>追加文本成功返回true</returns>
        public static bool AppendText(string FilePath, string Content, bool NewLine)
        {
            return AppendText(FilePath, Content, Encoding.UTF8, NewLine);
        }

        /// <summary>
        /// 追加新文本
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="Content">文本内容</param>
        /// <param name="encoding">文件编码格式</param>
        /// <param name="NewLine">是否换行</param>.
        ///  <returns>追加文本成功返回true</returns>
        public static bool AppendText(string FilePath, string Content, Encoding encoding, bool NewLine)
        {
            try
            {
                if (NewLine)
                    Content = "\r\n" + Content;
                File.AppendAllText(FilePath, Content, encoding);
            }
            catch (Exception ex) { PrintLog.Log(ex); return false; }
            return true;
        }

        /// <summary>
        /// 追加写入LIST到文件，使用UTF8编码
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="ContentList"></param>
        ///  <returns>追加文本成功返回true</returns>
        public static bool AppendList(string FilePath, List<string> ContentList)
        {
            return AppendList(FilePath, ContentList, Encoding.UTF8);
        }

        /// <summary>
        /// 追加写入LIST到文件
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="ContentList">文本数组</param>
        /// <param name="encoding">文件编码格式</param>
        ///  <returns>追加文本成功返回true</returns>
        public static bool AppendList(string FilePath, List<string> ContentList, Encoding encoding)
        {
            try
            {
                File.AppendAllLines(FilePath, ContentList, encoding);
            }
            catch (Exception ex) { PrintLog.Log(ex); return false; }
            return true;
        }

        /// <summary>
        /// 覆盖文件，用UTF8编码写入文本
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="Content">文本内容</param>
        ///  <returns>覆盖文件成功返回true</returns>
        public static bool WriteText(string FilePath, string Content)
        {
            return WriteText(FilePath, Content, Encoding.UTF8);
        }

        /// <summary>
        /// 覆盖文件，用指定编码写入文本
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="Content">文本内容</param>
        /// <param name="encoding">文件编码格式</param>
        ///  <returns>覆盖文件成功返回true</returns>
        public static bool WriteText(string FilePath, string Content, Encoding encoding)
        {
            try
            {
                FloderHelper.FloderExits(FloderNameHelper.GetFloderPath(FilePath), true);
                File.WriteAllText(FilePath, Content, encoding);
            }
            catch (Exception ex) { PrintLog.Log(ex); return false; }
            return true;
        }

        /// <summary>
        ///覆盖源文件，用UTF8编码写入List
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="Content">文本内容</param>
        ///  <returns>覆盖文件成功返回true</returns>
        public static bool WriteList(string FilePath, List<string> Content)
        {
            return WriteList(FilePath, Content, Encoding.UTF8);
        }

        /// <summary>
        ///  覆盖文件，用指定编码写入List
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="Content">文本内容</param>
        /// <param name="encoding">文件编码格式</param>
        ///  <returns>覆盖文件成功返回true</returns>
        public static bool WriteList(string FilePath, List<string> Content, Encoding encoding)
        {
            try
            {
                File.WriteAllLines(FilePath, Content, encoding);
            }
            catch (Exception ex) { PrintLog.Log(ex); return false; }
            return true;
        }

        /// <summary>
        ///读取一个文件所有行，使用UTF8编码，返回LIST。
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <returns>读取文件的所有行,读取失败返回  <![CDATA[ new List<string>();]]>而非空指针，请注意</returns>
        public static List<string> ReadAllLine(string FilePath)
        {
            return ReadAllLine(FilePath, Encoding.UTF8, false);
        }

        /// <summary>
        ///读取一个文件所有行，使用UTF8编码，返回LIST。
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="CreateFlie">设定参数CreateFlie为True可以同时创建文件</param>
        /// <returns>读取文件的所有行,读取失败返回  <![CDATA[ new List<string>();]]>而非空指针，请注意</returns>
        public static List<string> ReadAllLine(string FilePath, bool CreateFlie)
        {
            return ReadAllLine(FilePath, Encoding.UTF8, CreateFlie);
        }

        /// <summary>
        /// 读取一个文件所有行，使用指定编码，返回LIST。
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="encoding">文件编码格式</param>
        /// <param name="CreateFlie">设定参数CreateFlie为True可以同时创建文件</param>
        /// <returns>读取文件的所有行,读取失败返回  <![CDATA[ new List<string>();]]>而非空指针，请注意</returns>
        public static List<string> ReadAllLine(string FilePath, Encoding encoding, bool CreateFlie)
        {
            List<string> ReadAllLine = new List<string>();
            try
            {
                if (FileExits(FilePath))
                    ReadAllLine = File.ReadAllLines(FilePath, encoding).ToList<string>();
                else
                {
                    if (CreateFlie)
                        File.AppendAllText(FilePath, "", encoding);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            return ReadAllLine;
        }

        /// <summary>
        /// 选择文件
        /// </summary>
        /// <returns>返回选择的文件，如果没选择返回空字符串 ""</returns>
        public static string SelectFile()
        {
            return SelectFile("", "所有文件(*.*)|*.*");
        }

        /// <summary>
        /// 选择文件
        /// </summary>
        /// <param name="Filter">选择文件的规则</param>
        /// <returns>返回选择的文件，如果没选择返回空字符串 ""</returns>

        public static string SelectFile(string Filter)
        {
            return SelectFile("", Filter);
        }

        /// <summary>
        /// 选择文件  需要传入初始化上次记录的文件路径
        /// </summary>
        /// <param name="InitialDirectory">初始化上次记录的文件路径</param>
        /// <param name="Filter">选择文件的规则</param>
        /// <returns>返回选择的文件，如果没选择返回空字符串 ""</returns>

        public static string SelectFile(string InitialDirectory, string Filter)
        {
            List<string> MultiFile = SelectMultiFile(InitialDirectory, Filter);
            return ListHelper.GetFirst(MultiFile);
        }

        /// <summary>
        /// 选择多个文件  记住上次的路径
        /// </summary>
        /// <param name="InitialDirectory"></param>
        /// <param name="Filter"></param>
        /// <returns></returns>
        public static List<string> SelectMultiFile(string InitialDirectory = "", string Filter = "所有文件(*.*)|*.*")
        {
            List<string> FileList = new List<string>();
            using (OpenFileDialog dialog = InitFileDialog(InitialDirectory, Filter))
            {
                if (InitialDirectory != "")
                    dialog.InitialDirectory = InitialDirectory;
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    FileList = dialog.FileNames.ToList();
                    FileHelper.WriteText(SelectFileInfoTemp, FloderNameHelper.GetFloderPath(ListHelper.GetFirst(FileList)));
                }
            }
            return FileList;
        }

        /// <summary>
        /// 初始化文件选择框
        /// </summary>
        /// <param name="InitialDirectory"></param>
        /// <param name="Filter"></param>
        /// <returns></returns>
        private static OpenFileDialog InitFileDialog(string InitialDirectory, string Filter)
        {
            OpenFileDialog dialog = new OpenFileDialog
            {
                Multiselect = true,//该值确定是否可以选择多个文件
                Title = "请选择文件夹"
            };
            if (InitialDirectory != "")
                dialog.InitialDirectory = InitialDirectory;
            else
            {
                dialog.InitialDirectory = FileHelper.ReadAllText(SelectFileInfoTemp);
            }
            if (Filter != "")
                dialog.Filter = Filter;
            return dialog;
        }

        /// <summary>
        /// 文件重命名
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="NewFilePath"></param>
        public static void FileReName(string FilePath, string NewFilePath)
        {
            try
            {
                FileInfo fileInfo = new FileInfo(FilePath);
                fileInfo.MoveTo(NewFilePath);
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }
        }

        /// <summary>
        /// 判断文件大小是否超过了界限，超过返回false
        /// </summary>
        /// <param name="FileName"></param>
        /// <param name="FileSize">文件大小 KB</param>
        /// <returns></returns>
        public static bool JudgementOfSize(string FileName, int FileSize)
        {
            FileInfo fi = new FileInfo(FileName);
            if (fi.Length > 1024 * FileSize)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 修改文件md5
        /// </summary>
        /// <param name="Filename"></param>
        public static void ModifyMD5(string Filename)
        {
            if (!File.Exists(Filename))
            {
                Console.WriteLine("文件不存在");
            }
            else
            {
                //转化byte[]到list
                List<byte> ByteList = File.ReadAllBytes(Filename).ToList<byte>();
                //添加一个二进制随机数
                ByteList.AddRange(Encoding.Default.GetBytes(Convert.ToString(new Random().Next(), 2)).ToList<byte>());
                try
                {
                    File.WriteAllBytes(Filename, ByteList.ToArray());
                }
                catch (Exception ex)
                {
                    PrintLog.Log(ex);
                }
            }
        }

        /// <summary>
        /// 获取文件状态是否为只读
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <returns></returns>
        public static bool IsReadonly(string FilePath)
        {
            string FileStatus = File.GetAttributes(FilePath).ToString();
            if (FileStatus.IndexOf("ReadOnly") < 0)
                return false;
            return true;
        }

        /// <summary>
        /// 解除只读状态
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        public static void RelievingReadonly(string FilePath)
        {
            try
            {
                File.SetAttributes(FileHelper.SelectFile(), System.IO.FileAttributes.Normal);
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }
        }

        /// <summary>
        /// 获取文件大小 返回的是byte
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <returns></returns>
        public static long GetFileSizeForByte(string FilePath)
        {
            long lSize = 0;

            try
            {
                if (File.Exists(FilePath))
                    lSize = new FileInfo(FilePath).Length;
            }
            catch (Exception ex)
            {
                PrintLog.E(ex);
            }
            return lSize;
        }

        /// <summary>
        /// 获取文件大小 返回的是KB
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <returns></returns>
        public static double GetFileSizeForKB(string FilePath)
        {
            return (GetFileSizeForByte(FilePath) / 1024.00);
        }

        /// <summary>
        /// 去重复行和空行，然后重新覆盖这个文件
        /// </summary>
        public static void ToRepartLine(string FilePath)
        {
            List<string> AllLine = FileHelper.ReadAllLine(FilePath);

            File.Copy(FilePath, FilePath + ".bak", true);
            foreach (string line in File.ReadAllLines(FilePath))
            {
                if (line != "" && (!AllLine.Contains(line)))
                {
                    AllLine.Add(line.Trim());
                    Console.WriteLine("已读取" + line);
                }
            }
            File.WriteAllLines(FilePath, AllLine);
        }

        /// <summary>
        ///   移动文件  默认覆盖
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="NewFilePath"></param>
        public static void FileMove(string FilePath, string NewFilePath)
        {
            FileMove(FilePath, NewFilePath, true);
        }

        /// <summary>
        ///  移动文件  需要指示是否覆盖，若是不想覆盖，请调用FileNameHelper的createRandomFileName 创建不重复文件名
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="NewFilePath"></param>
        /// <param name="CoverFlag"></param>
        public static void FileMove(string FilePath, string NewFilePath, bool CoverFlag)
        {
            try
            {
                FloderHelper.FloderExits(Path.GetDirectoryName(NewFilePath), true);
                if (CoverFlag && File.Exists(NewFilePath))
                    FileDelete(NewFilePath);
                File.Move(FilePath, NewFilePath);
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }
        }

        /// <summary>
        /// 文件移动到文件夹
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="FloderPath"></param>
        /// <param name="CoverFlag"></param>
        public static void FileMoveToFloder(string FilePath, string FloderPath, bool CoverFlag)
        {
            FileMove(FilePath, $"{FloderPath}{FileNameHelper.GetFileName(FilePath)}", CoverFlag);
        }

        /// <summary>
        /// 文件移动到文件夹
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="FloderPath"></param>
        public static void FileMoveToFloder(string FilePath, string FloderPath)
        {
            FileMove(FilePath, $"{FloderPath}{FileNameHelper.GetFileName(FilePath)}", true);
        }

        /// <summary>
        /// 拷贝文件到文件夹
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="FloderPath"></param>

        public static void FileCopyToFloder(string FilePath, string FloderPath)
        {
            FileCopy(FilePath, $"{FloderPath}{FileNameHelper.GetFileName(FilePath)}", true);
        }

        /// <summary>
        /// 拷贝文件到文件夹
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="FloderPath"></param>
        /// <param name="CoverFlag"></param>
        public static void FileCopyToFloder(string FilePath, string FloderPath, bool CoverFlag)
        {
            FileCopy(FilePath, $"{FloderPath}{FileNameHelper.GetFileName(FilePath)}", CoverFlag);
        }

        /// <summary>
        /// 复制文件  需要指示是否覆盖，若是不想覆盖，请调用FileNameHelper的createRandomFileName 创建不重复文件名
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="NewFilePath"></param>

        public static void FileCopy(string FilePath, string NewFilePath)
        {
            FileCopy(FilePath, NewFilePath, true);
        }

        /// <summary>
        /// 复制文件  需要指示是否覆盖，若是不想覆盖，请调用FileNameHelper的createRandomFileName 创建不重复文件名
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <param name="NewFilePath"></param>
        /// <param name="CoverFlag">是否覆盖</param>
        public static void FileCopy(string FilePath, string NewFilePath, bool CoverFlag)
        {
            try
            {
                FloderHelper.FloderExits(Path.GetDirectoryName(NewFilePath), true);
                if (CoverFlag && File.Exists(NewFilePath))
                    FileDelete(NewFilePath);
                File.Copy(FilePath, NewFilePath);
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }
        }

        /// <summary>
        /// 删除文件的方法，会告诉你删除是否成功
        /// </summary>
        /// <param name="Filename"></param>
        /// <returns></returns>
        public static bool FileDelete(string Filename)
        {
            try
            {
                File.Delete(Filename);
                return true;
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
                return false;
            }
        }
    }
}